package cz.muni.fi.pa165.languageschool.service.impl;

import cz.muni.fi.pa165.languageschool.DataFetchException;
import cz.muni.fi.pa165.languageschool.utils.ETOConverter;
import cz.muni.fi.pa165.languageschool.Student;
import cz.muni.fi.pa165.languageschool.dao.StudentDao;
import cz.muni.fi.pa165.languageschool.dto.LectureTO;
import cz.muni.fi.pa165.languageschool.dto.LecturerTO;
import cz.muni.fi.pa165.languageschool.dto.StudentTO;
import cz.muni.fi.pa165.languageschool.service.LectureService;
import cz.muni.fi.pa165.languageschool.service.StudentService;
import java.util.ArrayList;
import java.util.Collection;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

/**
 * StudentService implementation
 *
 * @author Marketa Trachtova (255498) marketa.tr(at)gmail.com, Michal Fučík
 * (395624) michal.fuca.fucik(at)gmail.com
 */
@Service
public class StudentServiceImpl implements StudentService {

    final static Logger log = LoggerFactory.getLogger(StudentServiceImpl.class);

    private StudentDao studentDao;
    private LectureService lectureService;

    public StudentServiceImpl() {
    }

    public StudentServiceImpl(StudentDao dao) {
        if (dao == null) {
            throw new NullPointerException("Argument dao was null");
        }
        this.studentDao = dao;
    }

    public void setLectureService(LectureService lectureService) {
        if (lectureService == null) {
            throw new NullPointerException("Argument lectureService was null");
        }
        this.lectureService = lectureService;
    }

    public void setStudentDao(StudentDao studentDao) {
        if (studentDao == null) {
            throw new NullPointerException("Argumnt studentDao was null");
        }
        this.studentDao = studentDao;
    }

    public StudentDao getStudentDao() {
        return this.studentDao;
    }

    @Transactional
    @Override
    public void createStudent(StudentTO student) {
        log.info("***** SERVICE Student createStudent: {}", student);
        Student std = ETOConverter.convertStudentTO(student);
        if (student == null) {
            throw new NullPointerException("Argument student was null");
        }
        try {
            studentDao.createStudent(std);
            student.setId(std.getId());
        } catch (Exception ex) {
            throw new DataFetchException(ex.toString(), ex);
        }
    }

    @Transactional
    @Override
    public Collection<StudentTO> getAllStudents() {
        log.info("***** SERVICE Student getAllStudents");
        Collection<Student> got = null;
        Collection<StudentTO> res = new ArrayList<>();
        try {
            got = studentDao.getAllStudents();
            for (Student st : got) {
                StudentTO sto = ETOConverter.convertStudent(st);
                for (LectureTO l : sto.getEnrolledLectures()) {
                    LecturerTO lrr = lectureService.getLecturesLecturer(l);
                    l.setLecturer(lrr);
                }
                res.add(sto);
            }
        } catch (Exception ex) {
            throw new DataFetchException(ex.toString(), ex);
        }
        return res;
    }

    @Transactional
    @Override
    public StudentTO getStudent(Long id) {
        log.info("***** SERVICE Student getStudent: {}", id);
        Student std = null;
        StudentTO res = null;
        if (id == null) {
            throw new NullPointerException("Argument id was null");
        }
        try {
            std = studentDao.getStudent(id);
        } catch (Exception ex) {
            throw new DataFetchException(ex.toString(), ex);
        }

        res = ETOConverter.convertStudent(std);
        /* due to broken relation Lecture - Lecturer we have to obtain 
         * lecturers of each lecture this way
         */
        if (res != null) {
            for (LectureTO l : res.getEnrolledLectures()) {
                LecturerTO lrr = lectureService.getLecturesLecturer(l);
                l.setLecturer(lrr);
            }
        }
        return res;
    }

    /**
     * Debug System.out String helper (ignore it)
     *
     * @param str
     */
    private void dump(String str) {
        if (str == null) {
            System.out.println();
        } else {
            dump(null);
            System.out.println(str);
            dump(null);
        }
    }

    @Transactional
    @Override
    public void updateStudent(StudentTO student) {
        log.info("***** SERVICE Student updateStudent: {}", student);
        if (student == null) {
            throw new NullPointerException("Argument student was null");
        }
        try {
            studentDao.updateStudent(ETOConverter.convertStudentTO(student));
        } catch (Exception ex) {
            throw new DataFetchException(ex.toString(), ex);
        }
    }

    @Transactional
    @Override
    public void deleteStudent(StudentTO student) {
        log.info("***** SERVICE Student deleteStudent: {}", student);
        if (student == null) {
            throw new NullPointerException("Argument student was null");
        }
        try {
            studentDao.deleteStudent(ETOConverter.convertStudentTO(student));
        } catch (Exception ex) {
            throw new DataFetchException(ex.toString(), ex);
        }
    }

    @Transactional(readOnly = true)
    @Override
    public StudentTO findByUsername(String username) {
        log.info("***** SERVICE Student findByUsername: {}", username);
        Student std = null;
        StudentTO res = null;
        if (username == null) {
            throw new NullPointerException("Argument username was null");
        }
        try {
            std = studentDao.findByUsername(username);
        } catch (Exception ex) {
            throw new DataFetchException(ex.toString(), ex);
        }

        res = ETOConverter.convertStudent(std);
        /* due to purposely broken relation Lecture - Lecturer we have to obtain 
         * lecturers of each lecture by this way
         */
        if (res != null) {
            for (LectureTO l : res.getEnrolledLectures()) {
                LecturerTO lrr = lectureService.getLecturesLecturer(l);
                l.setLecturer(lrr);
            }
        }
        return res;
    }

}
